#include "connection.h"   // 包含自定义的头文件
#include <stdio.h>        // 标准输入输出头文件
#include <string.h>       // 字符串操作头文件
#include <unistd.h>       // UNIX 标准函数定义，用于 close()
#include <errno.h>        // 错误号定义，用于 errno
#include <netdb.h>        // 网络数据库操作，用于 getaddrinfo()
#include <arpa/inet.h>    // 网络地址转换头文件
#include <sys/socket.h>   // 套接字编程头文件
#include <netinet/in.h>   // Internet 协议族定义
#include <netinet/tcp.h>  // TCP 相关定义，用于 TCP_INFO

// 连接到服务器的函数
int connect_to_server(const char *server_ip, int server_port)
{
    int conn_fd;                   // 套接字文件描述符
    struct addrinfo hints, *res, *p; // 用于 getaddrinfo 的结构体
    char port_str[6];              // 端口号字符串，最大65535
    int rv;                        // 返回值

    // 准备 hints 结构体
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;     // 不指定 IPv4 或 IPv6
    hints.ai_socktype = SOCK_STREAM; // 流式套接字

    snprintf(port_str, sizeof port_str, "%d", server_port); // 将端口号转换为字符串

    // 获取地址信息
    if ((rv = getaddrinfo(server_ip, port_str, &hints, &res)) != 0)
    {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); // 打印错误信息
        return -1;
    }

    // 遍历所有结果并尝试连接
    for (p = res; p != NULL; p = p->ai_next)
    {
        // 创建套接字
        conn_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
        if (conn_fd == -1)
        {
            perror("socket"); // 打印错误信息
            continue;
        }

        // 尝试连接
        if (connect(conn_fd, p->ai_addr, p->ai_addrlen) == -1)
        {
            close(conn_fd); // 关闭套接字
            perror("connect"); // 打印错误信息
            continue;
        }

        break; // 成功连接后退出循环
    }

    if (p == NULL)
    {
        // 未能连接到任何地址
        fprintf(stderr, "无法连接到服务器 %s:%d\n", server_ip, server_port); // 打印错误信息
        conn_fd = -1;
    }

    freeaddrinfo(res); // 释放地址信息链表

    return conn_fd; // 返回套接字文件描述符
}

// 检查服务器连接状态的函数
int check_connection(int sock)
{
    struct tcp_info info;        // 存储 TCP 信息的结构体
    socklen_t len = sizeof(info); // 结构体长度

    if (sock <= 0)
    {
        return 0; // 套接字无效，返回未连接
    }

    if (getsockopt(sock, IPPROTO_TCP, TCP_INFO, &info, &len) == -1)
    {
        perror("getsockopt"); // 打印错误信息
        return 0;
    }

    if (info.tcpi_state == TCP_ESTABLISHED)
    {
        printf("服务器已连接\n"); // 打印连接状态
        return 1; // 返回已连接
    }
    else
    {
        printf("服务器已断开\n"); // 打印断开状态
        return 0; // 返回未连接
    }
}

